/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package org.cx1.service.impl;

import com.rits.cloning.Cloner;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import org.apache.commons.lang.StringUtils;
import org.cx1.dao.api.IListingDao;
import org.cx1.dao.api.IPhotoDao;
import org.cx1.dao.impl.ListingDao;
import org.cx1.dao.impl.PhotoDao;
import org.cx1.model.Amenity;
import org.cx1.model.Listing;
import org.cx1.model.Photo;
import org.cx1.model.Place;
import org.cx1.model.User;
import org.cx1.model.ds.MockDS;
import org.cx1.model.utils.KFurnishTypes;
import org.cx1.model.utils.KPlaceTypeIDs;
import org.cx1.model.utils.KPosterTypes;
import org.cx1.model.utils.KPropertyTypeIDs;
import org.cx1.model.utils.KPropertyTypes;
import org.cx1.model.utils.KStatusTypes;
import org.cx1.model.utils.ListingComparator;
import org.cx1.model.utils.PhotoComparator;
import org.cx1.model.utils.SearchOption;
import org.cx1.model.utils.ServiceResponse;
import org.cx1.service.api.IAmenityService;
import org.cx1.service.api.IListingService;
import org.cx1.service.api.IPhotoService;
import org.cx1.service.api.IPlaceService;
import org.cx1.service.api.IUserService;
import org.cx1.service.utils.IDGenerator;
import org.jsoup.Jsoup;

/**
 *
 * @author ECH
 */
public class DListingService implements IListingService {

    private IListingDao listingDao = new ListingDao();
    private IPhotoDao photoDao = new PhotoDao();
    
    private IPhotoService photoService = new DPhotoService();        
    private IUserService userService = new DUserService();
    private IPlaceService placeService = new DPlaceService();    
    private IAmenityService amenityService = new DAmenityService();
    
    private Cloner cloner = new Cloner();
    
    private static Object lock = new Object();
    
    @Override
    public ServiceResponse<List<Listing>> readAll(int offset, int limit) {
        ServiceResponse<List<Listing>> response = new ServiceResponse<List<Listing>>();
        List<Listing> listings = new ArrayList<Listing>();
        try {            
            List<Listing> records = listingDao.getAll();
            if (records != null && records.size() > 0) {
                //CX: sort first
                Collections.sort(records, new ListingComparator());
                
                if (offset == 0 && limit == 0) {
                    listings.addAll(cloneListings(records));
                }
                else if (offset < records.size() && limit < records.size()) {
                    listings.addAll(cloneListings(records.subList(offset, limit)));
                }         
                else {
                     listings.addAll(cloneListings(records));
                }
            }            
            
            if (listings != null && listings.size() > 0) {
                for (Listing listing : listings) {                    
                    populateListingAttributes(listing);
                }
            }            
            response.setResponse(listings);
            response.setSuccessful(true);            
        } 
        catch (Exception ex) {
            response.setResponse(null);
            response.setSuccessful(false);
            response.setMessage(ex.getMessage());
            response.setException(ex);
            ex.printStackTrace();            
        }
        return response;
    }

    @Override
    public ServiceResponse<Listing> read(String id) {
        ServiceResponse<Listing> response = new ServiceResponse<Listing>();
        Listing listing = null;
        try {            
            listing = listingDao.getById(id);
            populateListingAttributes(listing);            
            response.setResponse(listing);
            response.setSuccessful(true);            
        } 
        catch (Exception ex) {
            response.setResponse(null);
            response.setSuccessful(false);
            response.setMessage(ex.getMessage());
            response.setException(ex);
            ex.printStackTrace();            
        }
        return response;
    }

    @Override
    public ServiceResponse<String> create(Listing listing) {
        ServiceResponse<String> response = new ServiceResponse<String>();
        String id = null;        
        try {            
            Listing entry = new Listing();
            id = IDGenerator.generateID();
            
            entry.setId(id);            
            
            entry.setTitle( trimTitle(listing.getTitle()) );
            entry.setDescription(cleanHtmlFragment(listing.getDescription(), "id|style"));
            entry.setNotes(listing.getNotes());
            
            entry.setAddress(listing.getAddress());
            entry.setCountry(listing.getCountry());
            entry.setRegion(listing.getRegion());
            entry.setCity(listing.getCity());
            entry.setBarangay(listing.getBarangay());
            entry.setStreet(listing.getStreet());
            entry.setStructure(listing.getStructure());
            entry.setNumber(listing.getNumber());
            entry.setFloor(listing.getFloor());
            entry.setZip(listing.getZip());
            
            entry.setLat(listing.getLat());
            entry.setLng(listing.getLng());
            
            entry.setLeaseLongTerm(listing.isLeaseLongTerm());
            entry.setLeaseShortTerm(listing.isLeaseShortTerm());
            
            entry.setLongMonthRate(listing.getLongMonthRate());            
            entry.setShortDayRate(listing.getShortDayRate());
            entry.setShortWeekRate(listing.getShortWeekRate());
            entry.setShortMonthRate(listing.getShortMonthRate());
            
            entry.setLongMonthRateNum(listing.getLongMonthRateNum());
            entry.setShortMonthRateNum(listing.getShortMonthRateNum());
            entry.setShortWeekRateNum(listing.getShortWeekRateNum());
            entry.setShortDayRateNum(listing.getShortDayRateNum());
            
            entry.setSqArea(listing.getSqArea());                                                
            entry.setNumBedrooms(listing.getNumBedrooms());
            entry.setNumBathrooms(listing.getNumBathrooms());
                                    
            entry.setPropertyTypeID(listing.getPropertyTypeID());
            entry.setStatusTypeID(listing.getStatusTypeID());
            entry.setPosterTypeID(listing.getPosterTypeID());
            entry.setFurnishTypeID(listing.getFurnishTypeID());
            
            entry.setAvailable(true);
            entry.setVerified(false);
            entry.setPosted(true);
            entry.setPenalized(false);
                            
            entry.setImpressions(listing.getImpressions());
            entry.setViews(listing.getViews());
            
            entry.setPropertyTypeID(listing.getPropertyTypeID());
            entry.setStatusTypeID(listing.getStatusTypeID());
            entry.setPosterTypeID(listing.getPosterTypeID());
            entry.setFurnishTypeID(listing.getFurnishTypeID());
            
            entry.setCreatorID(listing.getCreatorID());
            
            entry.setRoomorama_id(listing.getRoomorama_id());
            entry.setRoomorama_shortDayRateUSD(listing.getRoomorama_shortDayRateUSD());
            entry.setRoomoramaListing(listing.isRoomoramaListing());
            
            entry.setPhotoIDs(listing.getPhotoIDs());
            entry.setAmenityIDs(listing.getAmenityIDs());
            entry.setPlaceIDs(listing.getPlaceIDs());
                
            entry.setActive(true);
            entry.setDateCreated(new Date());
            entry.setDateModified(new Date());
            
            entry.setPostDate(new Date());    
            entry.setExpiryDate(new Date());
            entry.setSpawnDate(new Date());
                                  
            //CX: auto set expiry date
            Calendar c = Calendar.getInstance();
            c.setTime(new Date());
            c.add(Calendar.DATE, 30); 
            entry.setExpiryDate(c.getTime());
                                   
            //CX: auto set place
            ServiceResponse<String> sr1 = this.placeService.readIDByTitle(listing.getCity());
            if (sr1.isSuccessful() && !StringUtils.isEmpty(sr1.getResponse())) {
                entry.getPlaceIDs().add(sr1.getResponse());
                
                ServiceResponse<Place> sr2 = this.placeService.read(sr1.getResponse());
                Place city = sr2.getResponse();
                if (city != null) {
                    if (StringUtils.isEmpty(entry.getLat())) {
                        entry.setLat(city.getLat());
                    }
                    if (StringUtils.isEmpty(entry.getLng())) {
                        entry.setLng(city.getLng());
                    }                    
                }
            }   
           
            listingDao.add(entry);            
            
            
            if (entry.getPlaceIDs() != null && entry.getPlaceIDs().size() > 0) {
                for (String placeID : entry.getPlaceIDs()) {    
                    listingDao.addPlaceRef(entry.getId(), placeID, "");
                }
            }            
            if (entry.getAmenityIDs() != null && entry.getAmenityIDs().size() > 0) {
                for (String amenityID : entry.getAmenityIDs()) {    
                    listingDao.addAmenityRef(entry.getId(), amenityID);
                }
            }
            
            response.setResponse(id);
            response.setSuccessful(true);            
        } 
        catch (Exception ex) {
            response.setResponse(null);
            response.setSuccessful(false);
            response.setMessage(ex.getMessage());
            response.setException(ex);
            ex.printStackTrace();            
        }
        return response; 
    }

    @Override
    public ServiceResponse<String> create(Listing listing, boolean verified, boolean available, boolean posted) {
        ServiceResponse<String> response = new ServiceResponse<String>();
        String id = null;        
        try {            
            Listing entry = new Listing();
            id = IDGenerator.generateID();
            
            entry.setId(id);            
            
            entry.setTitle( trimTitle(listing.getTitle()) );
            entry.setDescription(cleanHtmlFragment(listing.getDescription(), "id|style"));
            entry.setNotes(listing.getNotes());
            
            entry.setAddress(listing.getAddress());
            entry.setCountry(listing.getCountry());
            entry.setRegion(listing.getRegion());
            entry.setCity(listing.getCity());
            entry.setBarangay(listing.getBarangay());
            entry.setStreet(listing.getStreet());
            entry.setStructure(listing.getStructure());
            entry.setNumber(listing.getNumber());
            entry.setFloor(listing.getFloor());
            entry.setZip(listing.getZip());
            
            entry.setLat(listing.getLat());
            entry.setLng(listing.getLng());
            
            entry.setLeaseLongTerm(listing.isLeaseLongTerm());
            entry.setLeaseShortTerm(listing.isLeaseShortTerm());
            
            entry.setLongMonthRate(listing.getLongMonthRate());            
            entry.setShortDayRate(listing.getShortDayRate());
            entry.setShortWeekRate(listing.getShortWeekRate());
            entry.setShortMonthRate(listing.getShortMonthRate());
                        
            entry.setLongMonthRateNum(listing.getLongMonthRateNum());
            entry.setShortMonthRateNum(listing.getShortMonthRateNum());
            entry.setShortWeekRateNum(listing.getShortWeekRateNum());
            entry.setShortDayRateNum(listing.getShortDayRateNum());
                            
            entry.setSqArea(listing.getSqArea());                                                
            entry.setNumBedrooms(listing.getNumBedrooms());
            entry.setNumBathrooms(listing.getNumBathrooms());
                        
            entry.setPostDate(listing.getPostDate());    
            entry.setExpiryDate(listing.getExpiryDate());
            
            entry.setPropertyTypeID(listing.getPropertyTypeID());
            entry.setStatusTypeID(listing.getStatusTypeID());
            entry.setPosterTypeID(listing.getPosterTypeID());
            entry.setFurnishTypeID(listing.getFurnishTypeID());
            
            entry.setAvailable(available);
            entry.setVerified(verified);
            entry.setPosted(posted);
            entry.setPenalized(false);
                            
            entry.setImpressions(listing.getImpressions());
            entry.setViews(listing.getViews());
            
            entry.setPropertyTypeID(listing.getPropertyTypeID());
            entry.setStatusTypeID(listing.getStatusTypeID());
            entry.setPosterTypeID(listing.getPosterTypeID());
            entry.setFurnishTypeID(listing.getFurnishTypeID());
            
            entry.setCreatorID(listing.getCreatorID());
            
            entry.setRoomorama_id(listing.getRoomorama_id());
            entry.setRoomorama_shortDayRateUSD(listing.getRoomorama_shortDayRateUSD());
            entry.setRoomoramaListing(listing.isRoomoramaListing());
            
            entry.setPhotoIDs(listing.getPhotoIDs());
            entry.setAmenityIDs(listing.getAmenityIDs());
            entry.setPlaceIDs(listing.getPlaceIDs());
                
            entry.setActive(true);
            entry.setDateCreated(new Date());
            entry.setDateModified(new Date());
            
            entry.setPostDate(new Date());    
            entry.setExpiryDate(new Date());
            entry.setSpawnDate(new Date());
                                    
            //CX: auto set expiry date
            Calendar c = Calendar.getInstance();
            c.setTime(new Date());
            c.add(Calendar.DATE, 30); 
            entry.setExpiryDate(c.getTime());
                                   
            //CX: auto set place
            ServiceResponse<String> sr1 = this.placeService.readIDByTitle(listing.getCity());
            if (sr1.isSuccessful() && !StringUtils.isEmpty(sr1.getResponse())) {
                entry.getPlaceIDs().add(sr1.getResponse());
                
                ServiceResponse<Place> sr2 = this.placeService.read(sr1.getResponse());
                Place city = sr2.getResponse();
                if (city != null) {
                    if (StringUtils.isEmpty(entry.getLat())) {
                        entry.setLat(city.getLat());
                    }
                    if (StringUtils.isEmpty(entry.getLng())) {
                        entry.setLng(city.getLng());
                    }                    
                }
            }  
            
            listingDao.add(entry);
            
            if (entry.getPlaceIDs() != null && entry.getPlaceIDs().size() > 0) {
                for (String placeID : entry.getPlaceIDs()) {    
                    listingDao.addPlaceRef(entry.getId(), placeID, "");
                }
            }            
            if (entry.getAmenityIDs() != null && entry.getAmenityIDs().size() > 0) {
                for (String amenityID : entry.getAmenityIDs()) {    
                    listingDao.addAmenityRef(entry.getId(), amenityID);
                }
            }
            
            response.setResponse(id);
            response.setSuccessful(true);            
        } 
        catch (Exception ex) {
            response.setResponse(null);
            response.setSuccessful(false);
            response.setMessage(ex.getMessage());
            response.setException(ex);
            ex.printStackTrace();            
        }
        return response; 
    }
            
    @Override
    public synchronized ServiceResponse<Boolean> update(Listing listing) {
        ServiceResponse<Boolean> response = new ServiceResponse<Boolean>();
        boolean success = false;
        try {            
            String targetID = listing.getId();    
            Listing targetListing = listingDao.getById(targetID);
                     
            //CX: update dabase record
            if (targetListing != null) {                
                targetListing.setTitle(trimTitle(listing.getTitle()));
                targetListing.setDescription(cleanHtmlFragment(listing.getDescription(), "id|style"));
                targetListing.setNotes(listing.getNotes());
                
                targetListing.setCountry(listing.getCountry());
                targetListing.setRegion(listing.getRegion());
                targetListing.setCity(listing.getCity());
                targetListing.setBarangay(listing.getBarangay());
                targetListing.setStreet(listing.getStreet());
                targetListing.setStructure(listing.getStructure());
                targetListing.setNumber(listing.getNumber());
                targetListing.setFloor(listing.getFloor());
                targetListing.setZip(listing.getZip());
                
                targetListing.setLat(listing.getLat());
                targetListing.setLng(listing.getLng());
                
                targetListing.setLeaseLongTerm(listing.isLeaseLongTerm());
                targetListing.setLeaseShortTerm(listing.isLeaseShortTerm());

                targetListing.setLongMonthRate(listing.getLongMonthRate());            
                targetListing.setShortDayRate(listing.getShortDayRate());
                targetListing.setShortWeekRate(listing.getShortWeekRate());
                targetListing.setShortMonthRate(listing.getShortMonthRate());

                targetListing.setLongMonthRateNum(listing.getLongMonthRateNum());
                targetListing.setShortMonthRateNum(listing.getShortMonthRateNum());
                targetListing.setShortWeekRateNum(listing.getShortWeekRateNum());
                targetListing.setShortDayRateNum(listing.getShortDayRateNum());
                
                targetListing.setSqArea(listing.getSqArea());
                targetListing.setNumBedrooms(listing.getNumBedrooms());
                targetListing.setNumBathrooms(listing.getNumBathrooms());

                targetListing.setPostDate(listing.getPostDate());
                targetListing.setExpiryDate(listing.getExpiryDate());

                targetListing.setAvailable(listing.isAvailable());
                targetListing.setVerified(listing.isVerified());
                targetListing.setPosted(listing.isPosted());
                targetListing.setPenalized(listing.isPenalized());

                targetListing.setImpressions(listing.getImpressions());
                targetListing.setViews(listing.getViews());
                                
                targetListing.setPropertyTypeID(listing.getPropertyTypeID());
                targetListing.setStatusTypeID(listing.getStatusTypeID());
                targetListing.setPosterTypeID(listing.getPosterTypeID());
                targetListing.setFurnishTypeID(listing.getFurnishTypeID());
                
                targetListing.setCreatorID(listing.getCreatorID());

                targetListing.setRoomorama_id(listing.getRoomorama_id());
                targetListing.setRoomorama_shortDayRateUSD(listing.getRoomorama_shortDayRateUSD());
                targetListing.setRoomoramaListing(listing.isRoomoramaListing());
                
                targetListing.setPhotoIDs(listing.getPhotoIDs());
                targetListing.setAmenityIDs(listing.getAmenityIDs());
                targetListing.setPlaceIDs(listing.getPlaceIDs());
                
                targetListing.setActive(listing.isActive());
                targetListing.setDateModified(new Date());     

                //CX: sensitive
                if (listing.getDateCreated() != null) {                        
                    targetListing.setDateCreated(listing.getDateCreated());
                }                  
                
                listingDao.update(targetListing);
                
                //CX: clear places
                listingDao.deleteAllPlaceRef(targetListing.getId());
                
                //CX: add new places
                if (targetListing.getPlaceIDs() != null && targetListing.getPlaceIDs().size() > 0) {
                    for (String placeID : targetListing.getPlaceIDs()) {    
                        listingDao.addPlaceRef(targetListing.getId(), placeID, "");
                    }
                }            
                
                //CX: clear amenities
                listingDao.deleteAllAmenityRef(targetListing.getId());
                
                //CX: add new amenities
                if (targetListing.getAmenityIDs() != null && targetListing.getAmenityIDs().size() > 0) {
                    for (String amenityID : targetListing.getAmenityIDs()) {    
                        listingDao.addAmenityRef(targetListing.getId(), amenityID);
                    }
                }
                
                
                success = true;  
            }            
            response.setResponse(success);
            response.setSuccessful(true);            
        } 
        catch (Exception ex) {
            response.setResponse(null);
            response.setSuccessful(false);
            response.setMessage(ex.getMessage());
            response.setException(ex);
            ex.printStackTrace();            
        }
        return response; 
    }

    @Override
    public ServiceResponse<Boolean> delete(String id) {
        ServiceResponse<Boolean> response = new ServiceResponse<Boolean>();
        boolean success = false;
        try {            
            listingDao.deleteById(id);
            success = true;
            response.setResponse(success);
            response.setSuccessful(true);            
        } 
        catch (Exception ex) {
            response.setResponse(null);
            response.setSuccessful(false);
            response.setMessage(ex.getMessage());
            response.setException(ex);
            ex.printStackTrace();            
        }
        return response; 
    }

    @Override
    public ServiceResponse<Boolean> delete(String listingID, String userID) {
        ServiceResponse<Boolean> response = new ServiceResponse<Boolean>();
        boolean success = false;
        try {            
            Listing listing = listingDao.getById(listingID);
            if (StringUtils.equalsIgnoreCase(userID, listing.getCreatorID())) {
                listingDao.deleteById(listingID);
                success = true;                 
            }          
            response.setResponse(success);
            response.setSuccessful(true); 
        } 
        catch (Exception ex) {
            response.setResponse(null);
            response.setSuccessful(false);
            response.setMessage(ex.getMessage());
            response.setException(ex);
            ex.printStackTrace();            
        }
        return response; 
    }
    
    @Override
    public ServiceResponse<Listing> readByRoomoramaID(String id) {
        ServiceResponse<Listing> response = new ServiceResponse<Listing>();
        Listing listing = null;
        try {            
            List<Listing> records = listingDao.getAll();
            if (records != null && records.size() > 0) {
                for (Listing record : records) {
                    if (!StringUtils.isEmpty(record.getRoomorama_id()) && StringUtils.equalsIgnoreCase(record.getRoomorama_id(), id)) {
                        listing = cloneListing(record);
                        break;
                    }
                }
            }            
            populateListingAttributes(listing);            
            response.setResponse(listing);
            response.setSuccessful(true);            
        } 
        catch (Exception ex) {
            response.setResponse(null);
            response.setSuccessful(false);
            response.setMessage(ex.getMessage());
            response.setException(ex);
            ex.printStackTrace();            
        }
        return response; 
    }

    @Override
    public ServiceResponse<List<Listing>> readAllVerified(int offset, int limit, boolean verified) {
        ServiceResponse<List<Listing>> response = new ServiceResponse<List<Listing>>();
        List<Listing> listings = new ArrayList<Listing>();
        try {            
            List<Listing> records = listingDao.getAll();
            
            //CX: filter verified
            
            if (records != null && records.size() > 0) {
                
                List<Listing> cloneRecords = cloneListings(records);
                List<Listing> verifiedRecords = new ArrayList<Listing>();
                for (Listing clone : cloneRecords) {
                    if (clone.isVerified() == verified) {
                        verifiedRecords.add(clone);
                    }
                }
                
                if (offset == 0 && limit == 0) {
                    listings.addAll(cloneListings(verifiedRecords));
                }
                else if (offset < verifiedRecords.size() && limit < verifiedRecords.size()) {
                    listings.addAll(cloneListings(verifiedRecords.subList(offset, limit)));
                }              
            }            
            
            if (listings != null && listings.size() > 0) {
                for (Listing listing : listings) {                    
                    populateListingAttributes(listing);
                }
            }            
            response.setResponse(listings);
            response.setSuccessful(true);            
        } 
        catch (Exception ex) {
            response.setResponse(null);
            response.setSuccessful(false);
            response.setMessage(ex.getMessage());
            response.setException(ex);
            ex.printStackTrace();            
        }
        return response; 
    }

    @Override
    public ServiceResponse<List<Listing>> readAllPosted(int offset, int limit, boolean posted) {
        ServiceResponse<List<Listing>> response = new ServiceResponse<List<Listing>>();
        List<Listing> listings = new ArrayList<Listing>();
        try {            
            List<Listing> records = listingDao.getAll();
            
            //CX: filter posted            
            
            if (records != null && records.size() > 0) {
                
                List<Listing> cloneRecords = cloneListings(records);
                List<Listing> verifiedRecords = new ArrayList<Listing>();
                for (Listing clone : cloneRecords) {
                    if (clone.isPosted() == posted) {
                        verifiedRecords.add(clone);
                    }
                }
                
                if (offset == 0 && limit == 0) {
                    listings.addAll(cloneListings(verifiedRecords));
                }
                else if (offset < verifiedRecords.size() && limit < verifiedRecords.size()) {
                    listings.addAll(cloneListings(verifiedRecords.subList(offset, limit)));
                }              
            }            
            
            if (listings != null && listings.size() > 0) {
                for (Listing listing : listings) {                    
                    populateListingAttributes(listing);
                }
            }            
            response.setResponse(listings);
            response.setSuccessful(true);            
        } 
        catch (Exception ex) {
            response.setResponse(null);
            response.setSuccessful(false);
            response.setMessage(ex.getMessage());
            response.setException(ex);
            ex.printStackTrace();            
        }
        return response; 
    }

    @Override
    public ServiceResponse<List<Listing>> readAllPosted(int offset, int limit, boolean posted, int leaseTerm) {
        ServiceResponse<List<Listing>> response = new ServiceResponse<List<Listing>>();
        List<Listing> listings = new ArrayList<Listing>();
        try {            
            List<Listing> records = listingDao.getAll();
            
            //CX: filter posted     
            
            if (records != null && records.size() > 0) {
                
                List<Listing> cloneRecords = cloneListings(records);
                List<Listing> postedRecords = new ArrayList<Listing>();
                
                for (Listing clone : cloneRecords) {
                    if (clone.isPosted() == posted) {
                        if (leaseTerm == 1 && clone.isLeaseLongTerm()) {
                            postedRecords.add(clone);                            
                        }
                        else if (leaseTerm == 2 && clone.isLeaseShortTerm()) {
                            postedRecords.add(clone); 
                        }
                    }
                }
                                              
                if (offset == 0 && limit == 0) {
                    listings.addAll(cloneListings(postedRecords));
                }
                else if (offset < postedRecords.size() && limit < postedRecords.size()) {
                    listings.addAll(cloneListings(postedRecords.subList(offset, limit)));
                }              
            }            
            
            if (listings != null && listings.size() > 0) {
                for (Listing listing : listings) {                    
                    populateListingAttributes(listing);
                }
            }            
                        
            response.setResponse(listings);
            response.setSuccessful(true);            
        } 
        catch (Exception ex) {
            response.setResponse(null);
            response.setSuccessful(false);
            response.setMessage(ex.getMessage());
            response.setException(ex);
            ex.printStackTrace();            
        }
        return response;
    }

    @Override
    public ServiceResponse<List<Listing>> readAllRoomorama(int offset, int limit) {
        ServiceResponse<List<Listing>> response = new ServiceResponse<List<Listing>>();
        List<Listing> roomoramaListings = new ArrayList<Listing>();
        List<Listing> listings = new ArrayList<Listing>();
        try {            
            List<Listing> records = listingDao.getAll();
            
            if (records != null && records.size() > 0) {
                for (Listing record : records) {
                    if (record.isRoomoramaListing()) {
                        roomoramaListings.add(record);
                    }
                }
            }
            
            if (roomoramaListings != null && roomoramaListings.size() > 0) {
                if (offset == 0 && limit == 0) {
                    listings.addAll(cloneListings(roomoramaListings));
                }
                else if (offset < roomoramaListings.size() && limit < roomoramaListings.size()) {
                    listings.addAll(cloneListings(roomoramaListings.subList(offset, limit)));
                }              
            }            
            
            if (listings != null && listings.size() > 0) {
                for (Listing listing : listings) {                    
                    populateListingAttributes(listing);
                }
            }            
            response.setResponse(listings);
            response.setSuccessful(true);            
        } 
        catch (Exception ex) {
            response.setResponse(null);
            response.setSuccessful(false);
            response.setMessage(ex.getMessage());
            response.setException(ex);
            ex.printStackTrace();            
        }
        return response; 
    }

    @Override
    public ServiceResponse<List<Listing>> readUserListings(String userID, int offset, int limit) {
        ServiceResponse<List<Listing>> response = new ServiceResponse<List<Listing>>();
        List<Listing> listings = new ArrayList<Listing>();
        try {            
            List<Listing> records = listingDao.getAll();
            
            if (records != null && records.size() > 0) {
                if (offset == 0 && limit == 0) {
                    listings.addAll(cloneListings(records));
                }
                else if (offset < records.size() && limit < records.size()) {
                    listings.addAll(cloneListings(records.subList(offset, limit)));
                }              
            }            
            
            //CX: filter to only listings of target user
            if (!StringUtils.isEmpty(userID)) {
                List<Listing> tempList = new ArrayList<Listing>();
                
                if (listings != null && listings.size() > 0 ) {
                    for (Listing record : listings) {
                        if (StringUtils.equalsIgnoreCase(userID, record.getCreatorID())) {
                            tempList.add(record);
                        }
                    }                    
                }
                
                listings.clear();
                if (tempList != null && tempList.size() > 0) {
                    listings.addAll(tempList);
                }
            }
            
            //CX: fill up listings info
            if (listings != null && listings.size() > 0) {
                for (Listing listing : listings) {                    
                    populateListingAttributes(listing);
                }
            }            
            response.setResponse(listings);
            response.setSuccessful(true);            
        } 
        catch (Exception ex) {
            response.setResponse(null);
            response.setSuccessful(false);
            response.setMessage(ex.getMessage());
            response.setException(ex);
            ex.printStackTrace();            
        }
        return response;
    }

    @Override
    public ServiceResponse<List<Listing>> readPlaceListings(String placeID, int offset, int limit) {
        ServiceResponse<List<Listing>> response = new ServiceResponse<List<Listing>>();
        List<Listing> placeListings = new ArrayList<Listing>();
        List<Listing> listings = new ArrayList<Listing>();
        
        try {         
            ServiceResponse<List<Listing>> sr1 = this.readAll(0, 0);
            List<Listing> records = sr1.getResponse();
                           
            //CX: filter to only listings of target place
            if (records != null && records.size() > 0 && !StringUtils.isEmpty(placeID)) {
                List<Listing> tempList = new ArrayList<Listing>();
                
                if (records != null && records.size() > 0 ) {
                    for (Listing record : records) {
                        List<Place> listingPlaces = record.getPlaces();
                        
                        if (listingPlaces != null && listingPlaces.size() > 0) {
                            
                            for (Place place : listingPlaces) {
                                
                                if (StringUtils.equalsIgnoreCase(placeID, place.getId())) {
                                    tempList.add(record);
                                }
                            }                            
                        }
                    }                    
                }
                
                listings.clear();
                if (tempList != null && tempList.size() > 0) {
                    listings.addAll(tempList);
                }
            }            
            
            //CX: filter offset and limit
            if (listings != null && listings.size() > 0) {
                if (offset == 0 && limit == 0) {
                    placeListings.addAll(cloneListings(listings));
                }
                else if (offset < listings.size() && limit < listings.size()) {
                    placeListings.addAll(cloneListings(listings.subList(offset, limit)));
                }       
                else {
                    placeListings.addAll(cloneListings(listings));                    
                }            
            }        
            
            //CX: fill up listings info
            if (placeListings != null && placeListings.size() > 0) {
                for (Listing listing : placeListings) {                    
                    populateListingAttributes(listing);
                }
                Collections.sort(placeListings, new ListingComparator());
            }            
            response.setResponse(placeListings);
            response.setSuccessful(true);            
        } 
        catch (Exception ex) {
            response.setResponse(null);
            response.setSuccessful(false);
            response.setMessage(ex.getMessage());
            response.setException(ex);
            ex.printStackTrace();            
        }
        return response; 
    }

    @Override
    public ServiceResponse<List<Listing>> readPlaceListings(String placeID, int offset, int limit, int leaseTerm) {
        ServiceResponse<List<Listing>> response = new ServiceResponse<List<Listing>>();
        List<Listing> placeListings = new ArrayList<Listing>();
        List<Listing> listings = new ArrayList<Listing>();
        
        try {         
            ServiceResponse<List<Listing>> sr1 = this.readAll(0, 0);
            List<Listing> records = sr1.getResponse();
                           
            //CX: filter to only listings of target place
            if (records != null && records.size() > 0 && !StringUtils.isEmpty(placeID)) {
                List<Listing> tempList = new ArrayList<Listing>();
                
                if (records != null && records.size() > 0 ) {
                    for (Listing record : records) {
                        List<Place> listingPlaces = record.getPlaces();
                        
                        if (listingPlaces != null && listingPlaces.size() > 0) {
                            
                            for (Place place : listingPlaces) {
                                
                                if (StringUtils.equalsIgnoreCase(placeID, place.getId())) {
                                    tempList.add(record);
                                }
                            }                            
                        }
                    }                    
                }
                
                listings.clear();
                if (tempList != null && tempList.size() > 0) {
                    for (Listing listing : tempList) {
                        if (leaseTerm == 1 && listing.isLeaseLongTerm()) {
                            listings.add(listing);                            
                        }
                        else if (leaseTerm == 2 && listing.isLeaseShortTerm()) {
                            listings.add(listing); 
                        }
                    }
                }
            }            
            
            //CX: filter offset and limit
            if (listings != null && listings.size() > 0) {
                if (offset == 0 && limit == 0) {
                    placeListings.addAll(cloneListings(listings));
                }
                else if (offset < listings.size() && limit < listings.size()) {
                    placeListings.addAll(cloneListings(listings.subList(offset, limit)));
                }       
                else {
                    placeListings.addAll(cloneListings(listings));                    
                }            
            }        
            
            //CX: fill up listings info
            if (placeListings != null && placeListings.size() > 0) {
                for (Listing listing : placeListings) {                    
                    populateListingAttributes(listing);
                }
                Collections.sort(placeListings, new ListingComparator());
            }            
            response.setResponse(placeListings);
            response.setSuccessful(true);            
        } 
        catch (Exception ex) {
            response.setResponse(null);
            response.setSuccessful(false);
            response.setMessage(ex.getMessage());
            response.setException(ex);
            ex.printStackTrace();            
        }
        return response;
    }

    @Override
    public ServiceResponse<List<Listing>> readPlaceListingsRoomorama(String placeID, int offset, int limit) {
        ServiceResponse<List<Listing>> response = new ServiceResponse<List<Listing>>();
        List<Listing> placeListings = new ArrayList<Listing>();
        List<Listing> listings = new ArrayList<Listing>();
        
        try {         
            ServiceResponse<List<Listing>> sr1 = this.readAllRoomorama(0, 0);
            List<Listing> records = sr1.getResponse();
                           
            //CX: filter to only listings of target place
            if (records != null && records.size() > 0 && !StringUtils.isEmpty(placeID)) {
                List<Listing> tempList = new ArrayList<Listing>();
                
                if (records != null && records.size() > 0 ) {
                    for (Listing record : records) {
                        List<Place> listingPlaces = record.getPlaces();
                        
                        if (listingPlaces != null && listingPlaces.size() > 0) {
                            
                            for (Place place : listingPlaces) {
                                
                                if (StringUtils.equalsIgnoreCase(placeID, place.getId())) {
                                    tempList.add(record);
                                }
                            }                            
                        }
                    }                    
                }
                
                listings.clear();
                if (tempList != null && tempList.size() > 0) {
                    listings.addAll(tempList);
                }
            }            
            
            //CX: filter offset and limit
            if (listings != null && listings.size() > 0) {
                if (offset == 0 && limit == 0) {
                    placeListings.addAll(cloneListings(listings));
                }
                else if (offset < listings.size() && limit < listings.size()) {
                    placeListings.addAll(cloneListings(listings.subList(offset, limit)));
                }       
                else {
                    placeListings.addAll(cloneListings(listings));                    
                }            
            }        
            
            //CX: fill up listings info
            if (placeListings != null && placeListings.size() > 0) {
                for (Listing listing : placeListings) {                    
                    populateListingAttributes(listing);
                }
            }            
            response.setResponse(placeListings);
            response.setSuccessful(true);            
        } 
        catch (Exception ex) {
            response.setResponse(null);
            response.setSuccessful(false);
            response.setMessage(ex.getMessage());
            response.setException(ex);
            ex.printStackTrace();            
        }
        return response; 
    }

    @Override
    public ServiceResponse<List<Listing>> readShortTermListings(int offset, int limit) {
        throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
    }

    @Override
    public ServiceResponse<List<Listing>> readLongTermListings(int offset, int limit) {
        throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
    }

    @Override
    public ServiceResponse<List<Listing>> readRoomoramaListings(int offset, int limit) {
        ServiceResponse<List<Listing>> response = new ServiceResponse<List<Listing>>();
        List<Listing> listings = new ArrayList<Listing>();
        try {            
            List<Listing> records = listingDao.getAll();
            
            //CX: filter posted     
            
            if (records != null && records.size() > 0) {
                
                List<Listing> cloneRecords = cloneListings(records);
                List<Listing> roomoramaRecords = new ArrayList<Listing>();
                
                for (Listing clone : cloneRecords) {
                    if (clone.isRoomoramaListing()) {
                        roomoramaRecords.add(clone);   
                    }
                }
                                              
                if (offset == 0 && limit == 0) {
                    listings.addAll(cloneListings(roomoramaRecords));
                }
                else if (offset < roomoramaRecords.size() && limit < roomoramaRecords.size()) {
                    listings.addAll(cloneListings(roomoramaRecords.subList(offset, limit)));
                }              
            }            
            
            if (listings != null && listings.size() > 0) {
                for (Listing listing : listings) {                    
                    populateListingAttributes(listing);
                }
            }            
            response.setResponse(listings);
            response.setSuccessful(true);            
        } 
        catch (Exception ex) {
            response.setResponse(null);
            response.setSuccessful(false);
            response.setMessage(ex.getMessage());
            response.setException(ex);
            ex.printStackTrace();            
        }
        return response;
    }

    @Override
    public ServiceResponse<Boolean> setAvailability(String id, boolean available) {
        ServiceResponse<Boolean> response = new ServiceResponse<Boolean>();
        boolean success = false;
        try {             
            Listing listing = this.read(id).getResponse();
            //Listing listing = listingDao.getById(id);
            
            if (listing != null) {
                listing.setAvailable(available);
                this.update(listing);
            }
            success = true;
            response.setResponse(success);
            response.setSuccessful(success);            
        } 
        catch (Exception ex) {
            response.setResponse(null);
            response.setSuccessful(false);
            response.setMessage(ex.getMessage());
            response.setException(ex);
            ex.printStackTrace();            
        }
        return response;
    }

    @Override
    public ServiceResponse<Boolean> postListing(String id) {
        ServiceResponse<Boolean> response = new ServiceResponse<Boolean>();
        boolean success = false;
        try {         
            ServiceResponse<Listing> response1 = this.read(id);
            Listing record = response1.getResponse();
            //Listing record = listingDao.getById(id);
            
            if (StringUtils.equals(record.getId(), id)) {
                //CX: set as posted
                record.setPosted(true);

                //CX: set post date as well as date created and date modified
                Date postDate = new Date();
                record.setPostDate(postDate);
                record.setDateCreated(postDate);
                record.setDateModified(postDate);

                //CX: set expiry date
                Date expiryDate = null;
                Calendar c = Calendar.getInstance();
                c.setTime(new Date()); // Now use today date.
                c.add(Calendar.DATE, 30); // Adding 30 days
                expiryDate = c.getTime();
                record.setExpiryDate(expiryDate);
                
                this.update(record);
            }
            success = true;
            response.setResponse(success);
            response.setSuccessful(success);            
        } 
        catch (Exception ex) {
            response.setResponse(null);
            response.setSuccessful(false);
            response.setMessage(ex.getMessage());
            response.setException(ex);
            ex.printStackTrace();            
        }
        return response;
    }

    @Override
    public ServiceResponse<Boolean> unpostListing(String id) {
        ServiceResponse<Boolean> response = new ServiceResponse<Boolean>();
        boolean success = false;
        try {                     
            Listing record = this.read(id).getResponse();
            //Listing record = listingDao.getById(id);
            
            if (StringUtils.equals(record.getId(), id)) {
                record.setPosted(false);
                record.setPostDate(null);
                record.setExpiryDate(null);                
                this.update(record);
            }
            success = true;
            response.setResponse(success);
            response.setSuccessful(success);            
        } 
        catch (Exception ex) {
            response.setResponse(null);
            response.setSuccessful(false);
            response.setMessage(ex.getMessage());
            response.setException(ex);
            ex.printStackTrace();            
        }
        return response;
    }

    @Override
    public ServiceResponse<Boolean> verify(String id, boolean verified) {
        ServiceResponse<Boolean> response = new ServiceResponse<Boolean>();
        boolean success = false;
        try {            
            Listing listing = this.read(id).getResponse();
            //Listing listing = listingDao.getById(id);
            
            if (listing != null) {
                listing.setVerified(verified);
                ServiceResponse<Boolean> sr2 = this.update(listing);
                success = true;
            }            
            response.setResponse(success);
            response.setSuccessful(true);            
        } 
        catch (Exception ex) {
            response.setResponse(null);
            response.setSuccessful(false);
            response.setMessage(ex.getMessage());
            response.setException(ex);
            ex.printStackTrace();            
        }
        return response; 
    }

    @Override
    public ServiceResponse<Boolean> setPenalized(String id, boolean penalize) {
        ServiceResponse<Boolean> response = new ServiceResponse<Boolean>();
        boolean success = false;
        try {             
            Listing listing = this.read(id).getResponse();            
            if (listing != null) {
                //CX: set penalized
                listing.setPenalized(penalize);
                this.update(listing);
            }            
            success = true;
            response.setResponse(success);
            response.setSuccessful(success);            
        } 
        catch (Exception ex) {
            response.setResponse(null);
            response.setSuccessful(false);
            response.setMessage(ex.getMessage());
            response.setException(ex);
            ex.printStackTrace();            
        }
        return response;
    }

    @Override
    public ServiceResponse<Boolean> incrementImpressions(String id) {
        ServiceResponse<Boolean> response = new ServiceResponse<Boolean>();
        boolean success = false;
        try {             
            //CX: increment impression by 1
            this.listingDao.incrementImpressions(id);
            
            //Listing record = this.read(id).getResponse();
            //if (record != null) {
                //long impressions = record.getImpressions();
                //record.setImpressions(  impressions += 1 );
                //this.update(record);
            //}
            success = true;
            response.setResponse(success);
            response.setSuccessful(success);            
        } 
        catch (Exception ex) {
            response.setResponse(null);
            response.setSuccessful(false);
            response.setMessage(ex.getMessage());
            response.setException(ex);
            ex.printStackTrace();            
        }
        return response;
    }

    @Override
    public ServiceResponse<Boolean> incrementViews(String id) {
        ServiceResponse<Boolean> response = new ServiceResponse<Boolean>();
        boolean success = false;
        try {                         
            //CX: increment views by 1
            this.listingDao.incrementViews(id);
            //Listing record = this.read(id).getResponse();
            //if (record != null) {
                //long views = record.getViews();
                //record.setViews( views += 1 );                    
                //this.update(record);
            //}
            success = true;
            response.setResponse(success);
            response.setSuccessful(success);                       
        } 
        catch (Exception ex) {
            response.setResponse(null);
            response.setSuccessful(false);
            response.setMessage(ex.getMessage());
            response.setException(ex);
            ex.printStackTrace();            
        }
        return response;
    }

    @Override
    public ServiceResponse<Boolean> clearShortTermListings() {
        ServiceResponse<Boolean> response = new ServiceResponse<Boolean>();
        boolean success = false;
        try {            
            List<Listing> records = this.cloneListings(listingDao.getAll());            
            if (records != null && records.size() > 0) {
                
                for (int i = 0; i < records.size(); i++) {
                    Listing record = records.get(i);
                    
                    if (record.isLeaseShortTerm()) {
                        this.delete(record.getId());
                    }
                }
            }            
            success = true;
            response.setResponse(success);
            response.setSuccessful(true);             
        } 
        catch (Exception ex) {
            response.setResponse(null);
            response.setSuccessful(false);
            response.setMessage(ex.getMessage());
            response.setException(ex);
            ex.printStackTrace();            
        }
        return response; 
    }

    @Override
    public ServiceResponse<Boolean> clearLongTermListings() {
        ServiceResponse<Boolean> response = new ServiceResponse<Boolean>();
        boolean success = false;
        try {            
            List<Listing> records = this.cloneListings(listingDao.getAll());            
            if (records != null && records.size() > 0) {
                
                for (int i = 0; i < records.size(); i++) {
                    Listing record = records.get(i);
                    
                    if (record.isLeaseLongTerm()) {
                        this.delete(record.getId());
                    }
                }
            }            
            success = true;
            response.setResponse(success);
            response.setSuccessful(true);            
        } 
        catch (Exception ex) {
            response.setResponse(null);
            response.setSuccessful(false);
            response.setMessage(ex.getMessage());
            response.setException(ex);
            ex.printStackTrace();            
        }
        return response; 
    }

    @Override
    public ServiceResponse<Boolean> clearRoomoramaListings() {
        ServiceResponse<Boolean> response = new ServiceResponse<Boolean>();
        boolean success = false;
        try {            
            List<Listing> records = this.cloneListings(listingDao.getAll());            
            if (records != null && records.size() > 0) {
                
                for (int i = 0; i < records.size(); i++) {
                    Listing record = records.get(i);
                    
                    if (record.isRoomoramaListing()) {
                        this.delete(record.getId());
                    }
                }
            }            
            success = true;
            response.setResponse(success);
            response.setSuccessful(true);         
        } 
        catch (Exception ex) {
            response.setResponse(null);
            response.setSuccessful(false);
            response.setMessage(ex.getMessage());
            response.setException(ex);
            ex.printStackTrace();            
        }
        return response; 
    }

    public ServiceResponse<List<Listing>> readFiltered(SearchOption searchOption) {
        ServiceResponse<List<Listing>> response = new ServiceResponse<List<Listing>>();
        List<Listing> listings = new ArrayList<Listing>();
        try {            
            List<Listing> records = listingDao.getFiltered(searchOption);
            if (records != null && records.size() > 0) {
                listings.addAll(records);
            }
            if (listings != null && listings.size() > 0) {
                for (Listing listing : listings) {                    
                    populateListingAttributes(listing);
                }
            }            
            response.setResponse(listings);
            response.setSuccessful(true);            
        } 
        catch (Exception ex) {
            response.setResponse(null);
            response.setSuccessful(false);
            response.setMessage(ex.getMessage());
            response.setException(ex);
            ex.printStackTrace();            
        }
        return response;
    }
        
    public ServiceResponse<List<Listing>> readFilteredVerified(SearchOption searchOption) {
        ServiceResponse<List<Listing>> response = new ServiceResponse<List<Listing>>();
        List<Listing> listings = new ArrayList<Listing>();
        try {            
            List<Listing> records = listingDao.getFilteredVerified(searchOption);
            if (records != null && records.size() > 0) {
                listings.addAll(records);
            }
            if (listings != null && listings.size() > 0) {
                for (Listing listing : listings) {                    
                    populateListingAttributes(listing);
                }
            }            
            response.setResponse(listings);
            response.setSuccessful(true);            
        } 
        catch (Exception ex) {
            response.setResponse(null);
            response.setSuccessful(false);
            response.setMessage(ex.getMessage());
            response.setException(ex);
            ex.printStackTrace();            
        }
        return response;
    }
    
    @Override
    public ServiceResponse<Integer> countFiltered(SearchOption searchOption) {
        ServiceResponse<Integer> response = new ServiceResponse<Integer>();
        int count = 0;
        try {            
            count = listingDao.countFiltered(searchOption);      
            response.setResponse(count);
            response.setSuccessful(true);            
        } 
        catch (Exception ex) {
            response.setResponse(null);
            response.setSuccessful(false);
            response.setMessage(ex.getMessage());
            response.setException(ex);
            ex.printStackTrace();            
        }
        return response;
    }
    
    
    private void populateListingAttributes(Listing listing) {
        if (listing != null) {
            //CXL build display titles
            listing.setDisplayTitle(buildDisplayTitle(listing));
            listing.setUrlTitle(StringUtils.replaceChars(listing.getDisplayTitle(), " ", "-"));
            listing.setDisplayDescription(buildDisplayDescription(listing));
            listing.setDisplayShortDescription(buildDisplayShortDescription(listing));
            
            //CX: build address views
            listing.setAddress(buildAddress(listing));
            listing.setShortAddress(buildShortAddress(listing));
            listing.setCity(buildDisplayCity(listing));
            
            //CX: set rates
            if (StringUtils.isEmpty(listing.getLongMonthRate())) { 
                listing.setLongMonthRate("0.0");
            }
            if (StringUtils.isEmpty(listing.getShortMonthRate())) { 
                listing.setShortMonthRate("0.0");
            }
            if (StringUtils.isEmpty(listing.getShortWeekRate())) { 
                listing.setShortWeekRate("0.0");
            }
            if (StringUtils.isEmpty(listing.getShortDayRate())) { 
                listing.setShortDayRate("0.0");
            }
            
            //CX: populate property type
            listing.setPropertyType(KPropertyTypes.getPropertyType(listing.getPropertyTypeID()));
            
            //CX: populate status type
            listing.setStatusType(KStatusTypes.getStatusType(listing.getStatusTypeID()));
            
            //CX: populate poster type
            listing.setPosterType(KPosterTypes.getPosterType(listing.getPosterTypeID()));
            
            //CX: populate furnish type
            listing.setFurnishType(KFurnishTypes.getFurnishType(listing.getFurnishTypeID()));
                        
            //CX: populate places
            List<String> placeIDs = listingDao.getAllPlaceRefIDs(listing.getId());
            if (placeIDs != null && placeIDs.size() > 0) {
                listing.setPlaceIDs(placeIDs);
            }            
            listing.getPlaces().clear();                
            if (listing.getPlaceIDs() != null && listing.getPlaceIDs().size() > 0) {
                ServiceResponse<Place> sr1 = null;

                for (String placeID : listing.getPlaceIDs()) {
                    //sr1 = this.placeService.read(placeID);
                    sr1 = this.placeService.readShallow(placeID);

                    if (sr1.isSuccessful() && sr1.getResponse() != null) {
                        listing.getPlaces().add(sr1.getResponse());
                        
                        //CX: hack to populate community
                        Place place = sr1.getResponse();
                        if ( StringUtils.equals(place.getPlaceTypeID(), KPlaceTypeIDs.BUILDING) ||
                             StringUtils.equals(place.getPlaceTypeID(), KPlaceTypeIDs.VILLAGE)) {
                            listing.setCommunity(place);
                        }
                        if ( StringUtils.equals(place.getPlaceTypeID(), KPlaceTypeIDs.CITY)) {
                            listing.setCity_place(place);
                        }
                    }
                }                    
            }                
            
            //CX: populate amenities
            List<String> amenityIDs = listingDao.getAllAmenityRefIDs(listing.getId());
            if (amenityIDs != null && amenityIDs.size() > 0) {
                listing.setAmenityIDs(amenityIDs);
            }  
            
            listing.getAmenities().clear();                
            if (listing.getAmenityIDs() != null && listing.getAmenityIDs().size() > 0) {
                ServiceResponse<Amenity> sr2 = null;

                for (String amenityID : listing.getAmenityIDs()) {
                    sr2 = this.amenityService.read(amenityID);

                    if (sr2.isSuccessful() && sr2.getResponse() != null) {
                        listing.getAmenities().add(sr2.getResponse());
                    }
                }                    
            }                
            
            //CX: populate photos
            List<String> photoIDs = photoDao.getListingPhotoIds(listing.getId());
            if (photoIDs != null && photoIDs.size() > 0) {
                listing.setPhotoIDs(photoIDs);
            }  
            
            listing.getPhotos().clear(); 
            List<Photo> photos = new ArrayList<Photo>();
            if (listing.getPhotoIDs() != null && listing.getPhotoIDs().size() > 0) {
                ServiceResponse<Photo> sr2 = null;

                for (String photoID : listing.getPhotoIDs()) {
                    sr2 = this.photoService.read(photoID);                        
                    if (sr2.isSuccessful() && sr2.getResponse() != null) {
                        photos.add(sr2.getResponse());
                    }
                }                               
                Collections.sort(photos, new PhotoComparator());
                listing.setPhotos(photos);
            }
            
            //CX: populate primary            
            if (listing.getPhotos() != null && listing.getPhotos().size() > 0) {
                listing.setPrimaryPhoto(listing.getPhotos().get(0));
            }
            
            //CX: populate creator
            if (!StringUtils.isEmpty(listing.getCreatorID())) {
                ServiceResponse<User> sr4 = userService.read(listing.getCreatorID());
                if (sr4.isSuccessful() && sr4.getResponse() != null) {
                    listing.setCreator(sr4.getResponse());
                }
            }
        }            
    }
    
    private String buildDisplayTitle(Listing listing) {
        String displayTitle = "";
        
        if (!StringUtils.isEmpty(listing.getTitle())) {
            String tempTitle = listing.getTitle();            
            tempTitle = tempTitle.replaceAll("[^\\dA-Za-z0-9 ]", "");
            
            if (tempTitle.trim().length() > 64) {
                displayTitle = tempTitle.trim().substring(0, 64);
            }
            else {
                displayTitle = tempTitle.trim();
            }
        }
        return displayTitle;
    }
    
    private String cleanHtmlFragment(String htmlFragment, String attributesToRemove) {
        String fragment = "";
        if (!StringUtils.isEmpty(htmlFragment)) {
            fragment = htmlFragment.replaceAll("\\s+(?:" + attributesToRemove + ")\\s*=\\s*\"[^\"]*\"","");
        }
        return fragment;    
    }
    
    private String buildDisplayDescription(Listing listing) {
        String displayDescription = "";
        
        if (!StringUtils.isEmpty(listing.getDescription())) {
            String tempDescription = listing.getDescription();            
            tempDescription = tempDescription.replaceAll("[^\\dA-Za-z0-9 ]", "");
            
            
            tempDescription = cleanHtmlFragment(listing.getDescription(), "id|style");
    
            
            if (tempDescription.trim().length() > 2000) {
                //CX: remove max chars for now
                //descriptionTitle = tempDescription.trim().substring(0, 2000);
                displayDescription = tempDescription.trim();
            }
            else {
                displayDescription = tempDescription.trim();
            }
        }
        return displayDescription;
    }
    
    private String buildDisplayShortDescription(Listing listing) {
        String displayDescription = "";
        try {            
            if (!StringUtils.isEmpty(listing.getDescription())) {
                String tempDescription = listing.getDescription();            
                tempDescription = Jsoup.parse(tempDescription).text();
                
                if (tempDescription.trim().length() > 200) {
                    //CX: remove max chars for now
                    displayDescription = tempDescription.trim().substring(0, 200);
                }
                else {
                    displayDescription = tempDescription.trim();
                }
            }
        } catch (Exception ex) {
            
        }
        return displayDescription;
    }
    
    private String buildAddress(Listing listing) {
        StringBuilder sb = new StringBuilder(""); 
        if (!StringUtils.isEmpty(listing.getPropertyTypeID())) {
            if (listing.getPropertyTypeID().equals(KPropertyTypeIDs.CONDOMINIUM)) {
                if (!StringUtils.isEmpty(listing.getNumber())) {
                    sb.append( listing.getNumber() ).append(" ");
                }        
                if (!StringUtils.isEmpty(listing.getStructure())) {
                    sb.append( listing.getStructure() ).append(", ");
                }    
                if (!StringUtils.isEmpty(listing.getStreet())) {
                    sb.append( listing.getStreet() ).append(", ");
                }     
                if (!StringUtils.isEmpty(listing.getBarangay())) {
                    sb.append( listing.getBarangay() ).append(", ");
                }    
                if (!StringUtils.isEmpty(listing.getCity())) {
                    sb.append( listing.getCity() ).append(" ");
                }
                if (!StringUtils.isEmpty(listing.getZip())) {
                    sb.append( listing.getZip() );
                }            
            }
            else {
                if (!StringUtils.isEmpty(listing.getNumber())) {
                    sb.append( listing.getNumber() ).append(" ");
                }        
                if (!StringUtils.isEmpty(listing.getStreet())) {
                    sb.append( listing.getStreet() ).append(", ");
                }     
                if (!StringUtils.isEmpty(listing.getStructure())) {
                    sb.append( listing.getStructure() ).append(", ");
                }    
                if (!StringUtils.isEmpty(listing.getBarangay())) {
                    sb.append( listing.getBarangay() ).append(", ");
                }    
                if (!StringUtils.isEmpty(listing.getCity())) {
                    sb.append( listing.getCity() ).append(" ");
                }
                if (!StringUtils.isEmpty(listing.getZip())) {
                    sb.append( listing.getZip() );
                }            
            }            
        }
        return sb.toString();
    }
        
    private String buildShortAddress(Listing listing) {
        StringBuilder sb = new StringBuilder("");        
        if (!StringUtils.isEmpty(listing.getBarangay())) {
            sb.append( listing.getBarangay() ).append(", ");
        }    
        if (!StringUtils.isEmpty(listing.getCity())) {
            sb.append( listing.getCity() );
        }
        return sb.toString();
    }
    
    private String buildDisplayCity(Listing listing) {
        String displayCity = "";    
        try {
            if (!StringUtils.isEmpty(listing.getCity())) {
                displayCity = listing.getCity();
                displayCity = displayCity.replaceAll("city", "");
                displayCity = displayCity.replaceAll("City", "");
                displayCity = displayCity.trim();
            }             
        } catch (Exception ex) {
            
        }   
        return displayCity;
    }
        
    private String trimTitle(String title) {
        String trimmed = "";
        try {
            if (title.length() > 65) {
                trimmed = title.substring(0, 65);
            }
            else {
                trimmed = title;
            }            
        } 
        catch (Exception ex) {
            System.out.println("Title- " + title);
            ex.printStackTrace();
            trimmed = "";
        }
        return trimmed;
    }
    
    private List<Listing> cloneListings(List<Listing> listings) {
        List<Listing> cloneList = new ArrayList<Listing>(0);
        for (Listing listing : listings) {
            cloneList.add(cloneListing(listing));
        }
        return cloneList;
    }
    
    private Listing cloneListing(Listing listing) {
        return cloner.deepClone(listing);
    }
     
    
    public ServiceResponse<String> createImport(Listing listing) {
        ServiceResponse<String> response = new ServiceResponse<String>();
        String id = null;        
        try {            
            Listing entry = new Listing();   
            id = listing.getId();
            
            entry.setId(id);            
            
            entry.setTitle(listing.getTitle());
            entry.setDescription(listing.getDescription());
            entry.setNotes(listing.getNotes());
            
            entry.setAddress(listing.getAddress());
            entry.setCountry(listing.getCountry());
            entry.setRegion(listing.getRegion());
            entry.setCity(listing.getCity());
            entry.setBarangay(listing.getBarangay());
            entry.setStreet(listing.getStreet());
            entry.setStructure(listing.getStructure());
            entry.setNumber(listing.getNumber());
            entry.setFloor(listing.getFloor());
            entry.setZip(listing.getZip());
            
            entry.setLat(listing.getLat());
            entry.setLng(listing.getLng());
            
            entry.setLeaseLongTerm(listing.isLeaseLongTerm());
            entry.setLeaseShortTerm(listing.isLeaseShortTerm());
            
            entry.setLongMonthRate(listing.getLongMonthRate());            
            entry.setShortDayRate(listing.getShortDayRate());
            entry.setShortWeekRate(listing.getShortWeekRate());
            entry.setShortMonthRate(listing.getShortMonthRate());
            
            entry.setSqArea(listing.getSqArea());                                                
            entry.setNumBedrooms(listing.getNumBedrooms());
            entry.setNumBathrooms(listing.getNumBathrooms());
                                    
            entry.setPropertyTypeID(listing.getPropertyTypeID());
            entry.setStatusTypeID(listing.getStatusTypeID());
            entry.setPosterTypeID(listing.getPosterTypeID());
            entry.setFurnishTypeID(listing.getFurnishTypeID());
            
            entry.setAvailable(listing.isAvailable());
            entry.setVerified(listing.isVerified());
            entry.setPosted(listing.isPosted());
            entry.setPenalized(listing.isPenalized());
                            
            entry.setImpressions(listing.getImpressions());
            entry.setViews(listing.getViews());
            
            entry.setPropertyTypeID(listing.getPropertyTypeID());
            entry.setStatusTypeID(listing.getStatusTypeID());
            entry.setPosterTypeID(listing.getPosterTypeID());
            entry.setFurnishTypeID(listing.getFurnishTypeID());
            
            entry.setCreatorID(listing.getCreatorID());
            
            entry.setRoomorama_id(listing.getRoomorama_id());
            entry.setRoomorama_shortDayRateUSD(listing.getRoomorama_shortDayRateUSD());
            entry.setRoomoramaListing(listing.isRoomoramaListing());
            
            entry.setPhotoIDs(listing.getPhotoIDs());
            entry.setAmenityIDs(listing.getAmenityIDs());
            entry.setPlaceIDs(listing.getPlaceIDs());
                
            entry.setActive(listing.isActive());
            entry.setDateCreated(listing.getDateCreated());
            entry.setDateModified(listing.getDateModified());
            
            entry.setPostDate(listing.getPostDate());    
            entry.setExpiryDate(listing.getExpiryDate());
                                             
            entry.setPlaceIDs(listing.getPlaceIDs());
            entry.setAmenityIDs(listing.getAmenityIDs());
            
            listingDao.add(entry);            
                        
            if (entry.getPlaceIDs() != null && entry.getPlaceIDs().size() > 0) {
                for (String placeID : entry.getPlaceIDs()) {    
                    listingDao.addPlaceRef(entry.getId(), placeID, "");
                }
            }            
            if (entry.getAmenityIDs() != null && entry.getAmenityIDs().size() > 0) {
                for (String amenityID : entry.getAmenityIDs()) {    
                    listingDao.addAmenityRef(entry.getId(), amenityID);
                }
            }
            
            response.setResponse(id);
            response.setSuccessful(true);            
        } 
        catch (Exception ex) {
            response.setResponse(null);
            response.setSuccessful(false);
            response.setMessage(ex.getMessage());
            response.setException(ex);
            ex.printStackTrace();            
        }
        return response; 
    }
    
    public static void main(String[] argv) {
        IListingService listingService = new DListingService();
        Listing listing = null;
        for (int i = 1; i < 11; i++) {
            listing = new Listing();
            listing.setTitle("Listing Title - " + i);
            listingService.create(listing, true, true, true);
        }        
    }

}
